package cn.chenc.framework.excel.config;

import cn.chenc.framework.excel.converters.localdate.LocalDateNumberConverter;
import cn.chenc.framework.excel.converters.localdate.LocalDateStringConverter;
import cn.chenc.framework.excel.converters.localdatetime.LocalDateTimeNumberConverter;
import cn.chenc.framework.excel.converters.localdatetime.LocalDateTimeStringConverter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.DefaultConverterLoader;
import com.alibaba.excel.converters.bigdecimal.BigDecimalBooleanConverter;
import com.alibaba.excel.converters.bigdecimal.BigDecimalNumberConverter;
import com.alibaba.excel.converters.bigdecimal.BigDecimalStringConverter;
import com.alibaba.excel.converters.booleanconverter.BooleanBooleanConverter;
import com.alibaba.excel.converters.booleanconverter.BooleanNumberConverter;
import com.alibaba.excel.converters.booleanconverter.BooleanStringConverter;
import com.alibaba.excel.converters.bytearray.BoxingByteArrayImageConverter;
import com.alibaba.excel.converters.bytearray.ByteArrayImageConverter;
import com.alibaba.excel.converters.byteconverter.ByteBooleanConverter;
import com.alibaba.excel.converters.byteconverter.ByteNumberConverter;
import com.alibaba.excel.converters.byteconverter.ByteStringConverter;
import com.alibaba.excel.converters.date.DateNumberConverter;
import com.alibaba.excel.converters.date.DateStringConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleBooleanConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleNumberConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleStringConverter;
import com.alibaba.excel.converters.file.FileImageConverter;
import com.alibaba.excel.converters.floatconverter.FloatBooleanConverter;
import com.alibaba.excel.converters.floatconverter.FloatNumberConverter;
import com.alibaba.excel.converters.floatconverter.FloatStringConverter;
import com.alibaba.excel.converters.inputstream.InputStreamImageConverter;
import com.alibaba.excel.converters.integer.IntegerBooleanConverter;
import com.alibaba.excel.converters.integer.IntegerNumberConverter;
import com.alibaba.excel.converters.integer.IntegerStringConverter;
import com.alibaba.excel.converters.longconverter.LongBooleanConverter;
import com.alibaba.excel.converters.longconverter.LongNumberConverter;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.converters.shortconverter.ShortBooleanConverter;
import com.alibaba.excel.converters.shortconverter.ShortNumberConverter;
import com.alibaba.excel.converters.shortconverter.ShortStringConverter;
import com.alibaba.excel.converters.string.StringBooleanConverter;
import com.alibaba.excel.converters.string.StringErrorConverter;
import com.alibaba.excel.converters.string.StringNumberConverter;
import com.alibaba.excel.converters.string.StringStringConverter;
import com.alibaba.excel.converters.url.UrlImageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 　@description: EasyExcel 类型全局转化
 * 　@author 陈_C
 * 　@date 2020/8/26 17:41
 *
 */
@Configuration
public class CustomerDefaultConverterLoader {
    //存放写时用到的converter
    private static final String ALL_CONVERTER = "allConverter";
    //存放所有的converter
    private static final String WRITE_CONVERTER = "defaultWriteConverter";

    @Bean
    public DefaultConverterLoader init() throws IllegalAccessException {
        DefaultConverterLoader converters = new DefaultConverterLoader();
        Field[] fields = converters.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.getType() == Map.class) {
                Map<ConverterKeyBuild.ConverterKey, Converter> oldMap = (Map<ConverterKeyBuild.ConverterKey, Converter>) field.get(converters);
                //兼容高版本（2.2.0+）通过静态代码块初始化 复用旧代码 节省空间
                if (oldMap != null && !oldMap.isEmpty()) {
                    if (WRITE_CONVERTER.equalsIgnoreCase(field.getName())) {
                        putWriteConverter(oldMap, new LocalDateStringConverter());
                        putWriteConverter(oldMap,new LocalDateNumberConverter());
                        putWriteConverter(oldMap, new LocalDateTimeStringConverter());
                        putWriteConverter(oldMap,new LocalDateTimeNumberConverter());
                    } else if (ALL_CONVERTER.equalsIgnoreCase(field.getName())) {
                        putAllConverter(oldMap, new LocalDateStringConverter());
                        putAllConverter(oldMap,new LocalDateNumberConverter());
                        putAllConverter(oldMap, new LocalDateTimeStringConverter());
                        putAllConverter(oldMap,new LocalDateTimeNumberConverter());
                    }
                    field.set(converters, oldMap);
                } else {
                    setConverter(converters, field);
                }
            }
        }
        return converters;
    }

    private void setConverter(DefaultConverterLoader converters, Field field) throws IllegalAccessException {
        if (WRITE_CONVERTER.equalsIgnoreCase(field.getName())) {
            Map<ConverterKeyBuild.ConverterKey, Converter> map = new HashMap<>(32);
            //我们扩展的自定义转化器
            putWriteConverter(map, new LocalDateStringConverter());
            putWriteConverter(map,new LocalDateNumberConverter());
            putWriteConverter(map, new LocalDateTimeStringConverter());
            putAllConverter(map,new LocalDateTimeNumberConverter());
            //以下jar包自带的Converter
            putWriteConverter(map, new BigDecimalNumberConverter());
            putWriteConverter(map, new BooleanBooleanConverter());
            putWriteConverter(map, new ByteNumberConverter());
            putWriteConverter(map, new DateStringConverter());
            putWriteConverter(map, new DoubleNumberConverter());
            putWriteConverter(map, new FloatNumberConverter());
            putWriteConverter(map, new IntegerNumberConverter());
            putWriteConverter(map, new LongNumberConverter());
            putWriteConverter(map, new ShortNumberConverter());
            putWriteConverter(map, new StringStringConverter());
            putWriteConverter(map, new FileImageConverter());
            putWriteConverter(map, new InputStreamImageConverter());
            putWriteConverter(map, new ByteArrayImageConverter());
            putWriteConverter(map, new BoxingByteArrayImageConverter());
            putWriteConverter(map, new UrlImageConverter());
            field.set(converters, map);
        } else if (ALL_CONVERTER.equalsIgnoreCase(field.getName())) {
            Map<ConverterKeyBuild.ConverterKey, Converter> map = new HashMap<>(64);
            //我们扩展的自定义转化器
            putAllConverter(map, new LocalDateStringConverter());
            putAllConverter(map,new LocalDateNumberConverter());
            putAllConverter(map, new LocalDateTimeStringConverter());
            putAllConverter(map,new LocalDateTimeNumberConverter());
            //以下jar包自带的Converter
            putAllConverter(map, new BigDecimalBooleanConverter());
            putAllConverter(map, new BigDecimalNumberConverter());
            putAllConverter(map, new BigDecimalStringConverter());

            putAllConverter(map, new BooleanBooleanConverter());
            putAllConverter(map, new BooleanNumberConverter());
            putAllConverter(map, new BooleanStringConverter());

            putAllConverter(map, new ByteBooleanConverter());
            putAllConverter(map, new ByteNumberConverter());
            putAllConverter(map, new ByteStringConverter());

            putAllConverter(map, new DateNumberConverter());
            putAllConverter(map, new DateStringConverter());

            putAllConverter(map, new DoubleBooleanConverter());
            putAllConverter(map, new DoubleNumberConverter());
            putAllConverter(map, new DoubleStringConverter());

            putAllConverter(map, new FloatBooleanConverter());
            putAllConverter(map, new FloatNumberConverter());
            putAllConverter(map, new FloatStringConverter());

            putAllConverter(map, new IntegerBooleanConverter());
            putAllConverter(map, new IntegerNumberConverter());
            putAllConverter(map, new IntegerStringConverter());

            putAllConverter(map, new LongBooleanConverter());
            putAllConverter(map, new LongNumberConverter());
            putAllConverter(map, new LongStringConverter());

            putAllConverter(map, new ShortBooleanConverter());
            putAllConverter(map, new ShortNumberConverter());
            putAllConverter(map, new ShortStringConverter());

            putAllConverter(map, new StringBooleanConverter());
            putAllConverter(map, new StringNumberConverter());
            putAllConverter(map, new StringStringConverter());
            putAllConverter(map, new StringErrorConverter());
            field.set(converters, map);
        }
    }

    private void putWriteConverter(Map<ConverterKeyBuild.ConverterKey, Converter> map, Converter converter) {
        map.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
    }

    private void putAllConverter(Map<ConverterKeyBuild.ConverterKey, Converter> map, Converter converter) {
        map.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter);
    }
}
